<!DOCTYPE html><html lang="en"><head>
<title> 2016-5-25未命名文件---小书匠,在线编辑器,MARKDOWN,Evernote,文件版本</title>
  <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="()">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<style type="text/css">
a:focus {
  outline: thin dotted #333;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px;
}

a:hover,
a:active {
  outline: 0;
}
a {
  color: #0088cc;
  text-decoration: none;
}

a:hover {
  color: #005580;
  text-decoration: underline;
}

p {
  margin: 0 0 1.1em;
}

small {
  font-size: 85%;
}

strong {
  font-weight: bold;
}

em {
  font-style: italic;
}

cite {
  font-style: normal;
}


h1.story_title {
	margin: 0.7em 0;
}
.story_tags {
	margin: 0 0 1.2em;
}
h1,
h2,
h3,
h4,
h5,
h6 {
  margin: 0.5em 0;
	margin: 1.0em 0 .6em 0;
  font-family: inherit;
  font-weight: 500;
  line-height: 20px;
  color: inherit;
  text-rendering: optimizelegibility;
}

h1,
h2,
h3 {
  line-height: 40px;
}

h1 {
  font-size: 38.5px;
}

h2 {
  font-size: 31.5px;
}

h3 {
  font-size: 24.5px;
}

h4 {
  font-size: 17.5px;
}

h5 {
  font-size: 14px;
}

h6 {
  font-size: 11.9px;
}

ul,
ol {
  padding: 0;
  margin: 0 0 10px 35px;
}

ul ul,
ul ol,
ol ol,
ol ul {
  margin-bottom: 0;
}


dl {
  margin-bottom: 20px;
}

dt,
dd {
  line-height: 20px;
}

dt {
  font-weight: bold;
}

dd {
  margin-left: 10px;
}

hr {
  margin: 20px 0;
  border: 0;
  border-top: 1px solid #eeeeee;
  border-bottom: 1px solid #ffffff;
}

abbr[title],
abbr[data-original-title] {
  cursor: help;
  border-bottom: 1px dotted #999999;
}


blockquote {
  padding: 0 0 0 15px;
  margin: 0 0 20px;
  border-left: 5px solid #dddddd;
}

blockquote p {
  margin-bottom: 0;
  font-size: 16px;
  font-weight: 300;
  line-height: 25px;
}

blockquote small {
  display: block;
  line-height: 20px;
  color: #999999;
}

blockquote small:before {
  content: '\2014 \00A0';
}
q:before,
q:after,
blockquote:before,
blockquote:after {
  content: "";
}

address {
  display: block;
  margin-bottom: 20px;
  font-style: normal;
  line-height: 20px;
}
img {
	height: auto;
	max-width: 100%;
	vertical-align: middle;
	border: 0;
}

table {
  max-width: 100%;
  background-color: transparent;
  border-collapse: collapse;
  border-spacing: 0;
	border: 1px solid rgba(34,36,38,.15);
}
.tag.label{
display: inline-block;
vertical-align: baseline;
line-height: 1;
margin: 0em 0.125em;
background-color: #e8e8e8;
border-color: #e8e8e8;
background-image: none;
padding: 0.6em 0.8em;
color: rgba(0, 0, 0, 0.6);
text-transform: none;
font-weight: bold;
border-radius: 0.2857rem;
box-sizing: border-box;
font-size: 0.7428rem;
}

.table {
  width: 100%;
  margin-bottom: 20px;
}

.table th,
.table td {
  padding: 8px;
  line-height: 20px;
  text-align: left;
  vertical-align: top;
  border-top: 1px solid #dddddd;
}

.table th {
  font-weight: bold;
}

.table thead th {
  vertical-align: bottom;
}

.table caption + thead tr:first-child th,
.table caption + thead tr:first-child td,
.table colgroup + thead tr:first-child th,
.table colgroup + thead tr:first-child td,
.table thead:first-child tr:first-child th,
.table thead:first-child tr:first-child td {
  border-top: 0;
}

.table tbody + tbody {
  border-top: 2px solid #dddddd;
}

.table .table {
  background-color: #ffffff;
}


.table-striped tbody > tr:nth-child(odd) > td,
.table-striped tbody > tr:nth-child(odd) > th {
  background-color: #f9f9f9;
}

.table-celled.table tr td,.table-celled.table tr th {
    border-left: 1px solid rgba(34,36,38,.1)
}

.table-celled.table tr td:first-child,.table-celled.table tr th:first-child {
    border-left: none
}

.toc ul {
	list-style: none;
}
p {
	line-height: 1.6;
}
body>p {
  margin-bottom: 1.8em;
}
body>p>img.center,
body>p>a>img.center {
  display: block;
  margin: 0 auto;
  background-color: rgba(128,128,128,0.3);
}
body {
	font-family: 'Helvetica Neue', Helvetica, Tahoma, Arial, 'Hiragino Sans GB', STHeiti, "Microsoft YaHei", "微软雅黑", 'WenQuanYi Micro Hei', STXihei, "华文细黑", Heiti, "黑体", SimSun, "宋体", Song, sans-serif;
  font-size: 1.15em;
  font-weight: 100;
//  line-height: 1.8em;
  color: #2f2f2f;
}
em.cjk_emphasis{
	font-style: normal;
	font-family: Georgia,"Times New Roman",Times,"楷体","AR PL UKai CN", "NSimSun","Songti SC","SimSun",serif!important;
}
body dt,
body dd {
  line-height: 1.35em;
}
body code, body .xiaoshujiang_code {
//	background-color: #D6DBDF;
	border: 0;
  border-radius: 4px;
//  color: #2C3E50;
  font-size: 90%;
//  padding: 2px 4px;
}
code {
	background-color: #D6DBDF;
	border-radius: 4px;
	color: #2C3E50;
	padding: 2px 4px;
}
.xiaoshujiang_code ol{
	margin-bottom: 0px;
}
body h1 {
  line-height: 1.6;
}
body h2 {
  line-hieght: 1.1;
}
body h3 {
  line-height: 1.1;
}

/**
 * Treeview syntax highlighting based on highlight.js
 * Copyright (c) 2014-2015, Asciidocfx Team, (MIT Licensed)
 * https://github.com/asciidocfx/highlight-treeview.js
 */
.language-treeview.hljs{
  position: relative;
}
.hljs-folder,
.hljs-hiddenfile,
.hljs-file {
    position: relative;
    vertical-align: top;
    display: inline-block;
    height: 16px;
}
.hljs-folder:before,
.hljs-file:before,
.hljs-hiddenfile:before {
    top: 0;
    content: '';
    width: 14px;
    height: 12px;
    margin-top: 0px;
    margin-right: 3px;
    position: relative;
    display: inline-block;
    background-size: 14px;
    background-repeat: no-repeat;
}
.hljs-file:before,
.hljs-hiddenfile:before {
    height: 14px;
    margin-left: 1px;
}
.hljs-hiddenfile {
    opacity: 0.6;
}
.hljs-file.photo:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f1c5";
}
.hljs-file.plain:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f016";
}
.hljs-file.source:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f1c9";
}
.hljs-file.archive:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f1c6";
}
.hljs-file.audio:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f1c7";
}
.hljs-file.video:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f1c8";
}
.hljs-file.pdf:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f1c1";
}
.hljs-file.xls:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f1c3";
}
.hljs-file.doc:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f1c2";
}
.hljs-file.ppt:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f1c4";
}
.hljs-folder:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f114";
}
.hljs-hiddenfile:before {
	font: normal normal normal 14px/1 FontAwesome;
	content: "\f016";
}
.hljs-tvline {
    margin-left: 6px;
    position: absolute;
    text-indent: -99em;
    padding-bottom: 8px;
    vertical-align: top;
    display: inline-block;
    border-left-width: 1px;
    border-left-style: solid;
    border-left-color: rgb(94, 144, 117);
}
.hljs-folder-branch {
    width: 8px;
    height: 8px;
    margin-top: -1px;
    margin-left: 6px;
    text-indent: -99em;
    position: relative;
    vertical-align: top;
    display: inline-block;
    border-bottom-width: 1px;
    border-bottom-style: solid;
    border-bottom-color: rgb(94, 144, 117);
}
.hljs-folder-branch.win {
    width: 14px;
    margin-right: 2px;
}
.hljs-folder-last-branch {
    height: 7px;
    width: 7px;
    margin-left: 6px;
    text-indent: -99em;
    position: relative;
    vertical-align: top;
    display: inline-block;
    border-bottom-width: 1px;
    border-bottom-style: solid;
    border-bottom-color: rgb(94, 144, 117);
    border-left-width: 1px;
    border-left-style: solid;
    border-left-color: rgb(94, 144, 117);
}
.hljs-folder-last-branch.win {
    width: 13px;
    margin-right: 2px;
}


/**
 * Treeview syntax highlighting based on highlight.js
 */


.mark{
	border: 0;
  background-color: #ddf3e7;
  border-radius: 4px;
  color: #29754d;
  font-size: 90%;
  padding: 2px 4px;
}
.line_mark{
	border: 1px dashed #3A4C42;
}
code .mark, .xiaoshujiang_code .mark{
	border-radius: 0px;
	font-size: initial;
	padding: initial;
}
a.attachment{
	background-color: #ecf0f3;
	border: 1px solid #bec6cb;
	display: inline-block;
	padding: 5px;
	margin: 2px;
	min-width: 250px;
}
a.attachment i.fa{
	font-size: 3em;
  float: left;
  margin-right: 0.2em;
}
a.attachment .filename{
	vertical-align: top;
  text-align: left;
  font-weight: bold;
}
a.attachment .filesize{
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
  opacity: .6;
  font-size: 80%;
  white-space: nowrap;
}
.checkbox .checked{
	text-decoration: line-through;
}
.flow-chart, .sequence-diagram{
	text-align: center;
}
.plot, .plot-image{
	text-align: center;
	min-height: 200px;
	min-width: 200px;
}

pre, .xiaoshujiang_pre {
	line-height: initial !important;
	word-wrap: break-word;
	word-break: break-word;
}

.xiaoshujiang_pre {
	margin: 1em 0px;
	font-family: monospace;
	white-space: pre;
}

.story_align_left, .story_align_left .story_image_container {
	text-align: left;
}
.story_align_right, .story_align_right .story_image_container {
	text-align: right;
}
.story_align_center, .story_align_center .story_image_container {
	text-align: center;
}
.story_align_justify, .story_align_justify .story_image_container {
	text-align: justify;
}


/** 
 * code line nums
 */
code.hljs.code_linenums, .xiaoshujiang_code.hljs.code_linenums{
	position: relative;
}
.ol_linenums{
	padding: 0px;
	margin-left: 30px;
	border-left: 1px solid #e0e0e0;
}
.li_linenum{
	line-height: 20px;
	margin-left: 10px;
	list-style: none;
	counter-increment: lines 1;
}
.li_linenum.li_list_style{
	list-style: inherit;
	margin-left: 5px;
}
.li_linenum:before, .li_linenum_before_span{
	content: counter(lines, decimal);
  position: absolute;
  left: 0px;
  text-align: center;
  width: 2.5em;
	opacity: 0.5;
  vertical-align: top;
}
.li_linenum_before_span_hide{
	display: none;
}
.xiaoshujiang_code .code_line_break_hack{
	margin:0;
	border:0;
	border-top:0;
	border-bottom:0;
}
/** 
 * code line nums
 */
.mathjax-container{
	text-align: center;
}
div.mathjax{
	max-width: 700px;
	margin: 0 auto;
	font-size: 14px;
}
text{
	font-size: 14px;
}

/**
 * block image
 */

.story_image_container{
	text-align: center;
}
.story_image_container>.story_image{
	display: inline-block;
  position: relative;
	max-width: 80%;
}
.story_image_caption{
	border-bottom: 1px solid #d9d9d9;
	display: inline-block;
	color: #999;
	padding: 10px;
}
.story_image_blank_caption{
	border-bottom: 0px;
}
/**
.story_image:before, .story_image:after{
	content: '';
	position: absolute;
	z-index: -2;
	bottom: 13px;
	left: 10px;
	width: 50%;
	height: 20%;
	border-radius: 10px/90px;
	box-shadow: 0 15px 10px rgba(0,0,0,0.7);
	-webkit-transform: rotate(-3deg);
	-moz-transform: rotate(-3deg);
	-ms-transform: rotate(-3deg);
	-o-transform: rotate(-3deg);
	transform: rotate(-3deg);
}
.story_image:after {
	right: 10px;
	left: auto;
	-webkit-transform: rotate(3deg);
	-moz-transform: rotate(3deg);
	-ms-transform: rotate(3deg);
	-o-transform: rotate(3deg);
	transform: rotate(3deg);
}

**/
.story_image>img{
	border-radius: 0.3125em;
	box-shadow: 0 2px 4px 0 rgba(34,36,38,.12),0 2px 10px 0 rgba(34,36,38,.08);
}
.story_inline_image>img{
	max-width: 50%;
	vertical-align: bottom;
}

/*
    Paraíso (light)
    Created by Jan T. Sott (http://github.com/idleberg)
    Inspired by the art of Rubens LP (http://www.rubenslp.com.br)
*/

/* Paraíso Comment */
.hljs-comment,
.hljs-title {
  color: #776e71;
}

/* Paraíso Red */
.hljs-variable,
.hljs-attribute,
.hljs-tag,
.hljs-regexp,
.hljs-name,
.ruby .hljs-constant,
.xml .hljs-tag .hljs-title,
.xml .hljs-pi,
.xml .hljs-doctype,
.html .hljs-doctype,
.css .hljs-id,
.css .hljs-class,
.css .hljs-pseudo {
  color: #ef6155;
}

/* Paraíso Orange */
.hljs-number,
.hljs-preprocessor,
.hljs-built_in,
.hljs-literal,
.hljs-params,
.hljs-constant {
  color: #f99b15;
}

/* Paraíso Yellow */
.ruby .hljs-class .hljs-title,
.css .hljs-rule .hljs-attribute {
  color: #fec418;
}

/* Paraíso Green */
.hljs-string,
.hljs-value,
.hljs-inheritance,
.hljs-header,
.ruby .hljs-symbol,
.xml .hljs-cdata {
  color: #48b685;
}

/* Paraíso Aqua */
.css .hljs-hexcolor {
  color: #5bc4bf;
}

/* Paraíso Blue */
.hljs-function,
.python .hljs-decorator,
.python .hljs-title,
.ruby .hljs-function .hljs-title,
.ruby .hljs-title .hljs-keyword,
.perl .hljs-sub,
.javascript .hljs-title,
.coffeescript .hljs-title {
  color: #06b6ef;
}

/* Paraíso Purple */
.hljs-keyword,
.javascript .hljs-function {
  color: #815ba4;
}

.hljs {
  display: block;
  overflow-x: auto;
  background: #e7e9db;
  color: #4f424c;
  padding: 0.5em;
  -webkit-text-size-adjust: none;
}

.coffeescript .javascript,
.javascript .xml,
.tex .hljs-formula,
.xml .javascript,
.xml .vbscript,
.xml .css,
.xml .hljs-cdata {
  opacity: 0.5;
}



</style>
</head><body>
<div><div class="preview" id="wmd-preview">

	<div class="preview"><h1 id="e2809ce699bae883bde2809de5aeb6e5b185e7b3bbe7bb9fe58e9fe79086e58f8ae6b581e7a88b"><a name="e2809ce699bae883bde2809de5aeb6e5b185e7b3bbe7bb9fe58e9fe79086e58f8ae6b581e7a88b" target="_blank"></a>“智能”家居系统原理及流程</h1>
<p><a href="http://bbs.elecfans.com/jishu_606389_1_1.html" target="_blank">之前发了一个介绍</a>，拍了一个演示的视频，没看过的可以先看一下。主要就是实现手机对设备的控制以及获得设备的数据，由设备+服务器+客户端组成。流程以及使用到哪些技术等都未进行说明，这次来说一下吧，主要是说明主要的流程及重要的逻辑部分，那些细到哪个数组这样的细节当然省略，还有代码的结构也忽略啦，一下所有逻辑和代码均为应用层滴哦~~。</p>
<h1 id="e4b880efbc9ae7b3bbe7bb9fe7bb84e68890e58f8ae6b689e58f8ae588b0e79a84e68a80e69caf"><a name="e4b880efbc9ae7b3bbe7bb9fe7bb84e68890e58f8ae6b689e58f8ae588b0e79a84e68a80e69caf" target="_blank"></a>一：系统组成及涉及到的技术</h1>
<h2 id="120e8aebee5a487efbc88e7a1ace4bbb6e5b58ce585a5e5bc8fe8bdafe4bbb6efbc89"><a name="120e8aebee5a487efbc88e7a1ace4bbb6e5b58ce585a5e5bc8fe8bdafe4bbb6efbc89" target="_blank"></a>1. 设备（硬件+嵌入式软件）</h2>
<ul>
<li><p>角色：作为设备存在，上电时登录服务器，可以随时与服务器进行通信、数据交换，并根据服务器的指令执行相应的动作</p></li>
<li><p>硬件：
</p><ul>
<li><p>MCU: 任何MCU都可以滴，这里可以用cannon，也可以用其它MCU</p></li>
<li><p>外设：要感知的数据的传感器和执行器，以及传输用的wifi（这里使用esp8266）</p></li>
</ul>
</li>
<li><p>IDE: 因为是用STM32，所以当然是MDK,版本&gt;=5，或者eclipse，或者文本编辑器+gcc，随你便</p></li>
<li><p>语言：c语言或者C++,cannon官方的库是c语言，我自己之前一直都是用的C++/C混合的方式</p></li>
<li><p>相关技术：C/C++基本语法，USART,ADC,GPIO,PWM等片上驱动，片外模块的驱动（如wifi模块、传感器、执行器驱动），网络通信应用，CRC校验，加密算法</p></li>
</ul>
<h2 id="220e69c8de58aa1e599a8"><a name="220e69c8de58aa1e599a8" target="_blank"></a>2. 服务器</h2>
<ul>
<li><p>角色：作为服务器，作为用户与设备交互的中间人以及数据管理等。监听来自设备的登录请求、紧急消息以及向设备发送控制、查询命令；监听用户手机端的登录，用户发起的查询、控制命令等</p></li>
<li><p>语言：java</p></li>
<li><p>IDE:eclipse/Myeclipse</p></li>
<li><p>相关技术：java基本语法，多线程，socket通信，数据库相关操作，http通信</p></li>
</ul>
<h2 id="320e6898be69cbae7abafefbc88androidefbc89e38082"><a name="320e6898be69cbae7abafefbc88androidefbc89e38082" target="_blank"></a>3. 手机端（Android）。</h2>
<ul>
<li><p>角色：作为用户与设备交互的接口。用户使用手机端应用进行登录、控制设备、查询设备状态等等</p></li>
<li><p>语言：java</p></li>
<li><p>IDE:Android Studio 2.1</p></li>
<li><p>相关技术：Activity相关界面设计，java基础语法，多线程，socket通信，sharepreference，Android相关类库使用</p></li>
</ul>
<h1 id="e4ba8cefbc9ae58d8fe8aeae"><a name="e4ba8cefbc9ae58d8fe8aeae" target="_blank"></a>二：协议</h1>
<h2 id="320e9809ae4bfa1e9a1bae5ba8fe59bbe"><a name="320e9809ae4bfa1e9a1bae5ba8fe59bbe" target="_blank"></a>3. 通信顺序图</h2>
<p></p><div class="story_image_container story_block_image"><div class="story_image"><img src="" name="images/QQ截图20160525233718.png" alt="enter description here" title="QQ截图20160525233718.png"></div><br><div class="story_image_caption ">QQ截图20160525233718.png</div></div><p></p>
<h2 id="220e69c8de58aa1e599a83c-3ee8aebee5a487"><a name="220e69c8de58aa1e599a83c-3ee8aebee5a487" target="_blank"></a>2. 服务器&lt;----&gt;设备</h2>
<table class="table table-striped table-celled  ">
<thead>
<tr>
<th>帧头</th>
<th>数据类型</th>
<th>操作类型</th>
<th>设备号</th>
<th>UTC时间戳</th>
<th>信息长度</th>
<th>信息</th>
<th>CRC校验码</th>
</tr>
</thead>
<tbody>
<tr>
<td>2字节</td>
<td>2字节</td>
<td>1字节</td>
<td>6字节</td>
<td>6字节</td>
<td>2字节</td>
<td>N字节</td>
<td>2字节</td>
</tr>
<tr>
<td>0xabac</td>
<td></td>
<td>0x01:控制请求<br>0x02:信息响应<br>0x03:信息询问</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>前面所有的CRC16值</td>
</tr>
</tbody>
</table>
<h2 id="320e6898be69cbae7abaf3c-3ee69c8de58aa1e599a8"><a name="320e6898be69cbae7abaf3c-3ee69c8de58aa1e599a8" target="_blank"></a>3. 手机端&lt;----&gt;服务器</h2>
<table class="table table-striped table-celled  ">
<thead>
<tr>
<th>帧头</th>
<th>数据类型</th>
<th>操作类型</th>
<th>session码</th>
<th>UTC时间戳</th>
<th>信息长度</th>
<th>信息</th>
<th>CRC校验码</th>
</tr>
</thead>
<tbody>
<tr>
<td>2字节</td>
<td>2字节</td>
<td>1字节</td>
<td>32字节</td>
<td>6字节</td>
<td>2字节</td>
<td>N字节</td>
<td>2字节</td>
</tr>
<tr>
<td>0xabac</td>
<td></td>
<td>0x01:控制请求<br>0x02:信息响应<br>0x03:信息询问</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>前面所有的CRC16值</td>
</tr>
</tbody>
</table>
<h1 id="e4ba8cefbc9ae8aebee5a487e7abafe5ba94e794a8e5b182e7a88be5ba8fe6b581e7a88be58f8ae4bba3e7a081"><a name="e4ba8cefbc9ae8aebee5a487e7abafe5ba94e794a8e5b182e7a88be5ba8fe6b581e7a88be58f8ae4bba3e7a081" target="_blank"></a>二：设备端应用层程序流程及代码</h1>
<p></p><div class="story_image_container story_block_image"><div class="story_image"><img src="" name="images/QQ截图20160525233601.png" alt="enter description here" title="QQ截图20160525233601.png"></div><br><div class="story_image_caption ">QQ截图20160525233601.png</div></div><p></p>
<pre class="xiaoshujiang_code_container"><code class="language-cpp hljs"><span class="hljs-comment">/**
  *初始化
  */</span>
<span class="hljs-keyword">void</span> App::Init()
{
    <span class="hljs-comment">//关闭LED</span>
    light.Off();
    <span class="hljs-comment">//步进电机失能</span>
    stepMotor.Disable();
    <span class="hljs-comment">//设置步进电机速度，值越小速度越大</span>
    stepMotor.Run(<span class="hljs-keyword">true</span>,<span class="hljs-number">2</span>);
    <span class="hljs-comment">//初始化wifi</span>
    WifiInit();
    
    TaskManager::DelayS(<span class="hljs-number">5</span>);
    <span class="hljs-keyword">if</span>(!SignIn())
        com1&lt;&lt;<span class="hljs-string">"sign in fail!!!!!!!!!!!!\n\n\n"</span>;
    
    com1&lt;&lt;<span class="hljs-string">"initialize complete!\n"</span>;
}

<span class="hljs-comment">/**
  *循环体
  *@pre 传感器值已经在loop前获取到成员变量中
  */</span>
<span class="hljs-keyword">void</span> App::loop()
{
    <span class="hljs-keyword">static</span> <span class="hljs-keyword">float</span> time;
    <span class="hljs-keyword">if</span>(TaskManager::Time()-time&gt;=<span class="hljs-number">20</span>)
    {
        time = TaskManager::Time();
        com1&lt;&lt;<span class="hljs-string">"."</span>;
    }
    <span class="hljs-comment">//硬件健康状态检查</span>
    <span class="hljs-keyword">if</span>(!CheckHardware())
        com1&lt;&lt;<span class="hljs-string">"haredware error!\n"</span>;

    
    <span class="hljs-comment">//连接状态检查</span>
    <span class="hljs-keyword">if</span>(!CheckConnectionToServer())
        com1&lt;&lt;<span class="hljs-string">"connection to server error!\n"</span>;
    
    
    <span class="hljs-comment">//接收来自服务器的数据</span>
    ReceiveAndDeal();
}

<span class="hljs-keyword">void</span> App::WifiInit()
{
    <span class="hljs-comment">//WIFI initialize</span>
    <span class="hljs-keyword">if</span>(!wifi.Kick())<span class="hljs-comment">//检查连接</span>
    {
        com1&lt;&lt;<span class="hljs-string">"no wifi!\n\n\n"</span>;
        light.Blink(<span class="hljs-number">3</span>,<span class="hljs-number">300</span>);
        <span class="hljs-keyword">return</span>;
    }
    <span class="hljs-keyword">else</span>
        com1&lt;&lt;<span class="hljs-string">"wifi is healthy\n"</span>;
    wifi.SetEcho(<span class="hljs-keyword">false</span>);<span class="hljs-comment">//关闭回响</span>
    wifi.SetMode(esp8266::esp8266_MODE_STATION_AP,esp8266::esp8266_PATTERN_DEF);<span class="hljs-comment">//设置为station+ap模式</span>
    wifi.SetMUX(<span class="hljs-keyword">false</span>);<span class="hljs-comment">//单连接模式</span>
    wifi.SetApParam(mApSetName,mApSetPasswd,esp8266::esp8266_PATTERN_DEF);<span class="hljs-comment">//设置热点信息</span>
    wifi.JoinAP(mApJoinName,mApJoinPasswd,esp8266::esp8266_PATTERN_DEF);<span class="hljs-comment">//加入AP</span>
    
    <span class="hljs-comment">//连接服务器</span>
    <span class="hljs-keyword">if</span>(!wifi.Connect((<span class="hljs-keyword">char</span>*)<span class="hljs-string">"192.168.191.1"</span>,<span class="hljs-number">8090</span>,Socket_Type_Stream,Socket_Protocol_IPV4))
    {
        com1&lt;&lt;<span class="hljs-string">"connect server fail!\n\n\n"</span>;
        light.Blink(<span class="hljs-number">4</span>,<span class="hljs-number">300</span>);
        <span class="hljs-keyword">return</span>;
    }
    com1&lt;&lt;<span class="hljs-string">"WIFI initialize complete!\n"</span>;
    light.Blink(<span class="hljs-number">2</span>,<span class="hljs-number">200</span>);
    light.Off();
}

</code></pre>
<h1 id="e4b889efbc9ae69c8de58aa1e599a8e7abafe5ba94e794a8e5b182e7a88be5ba8fe6b581e7a88be58f8ae4bba3e7a081"><a name="e4b889efbc9ae69c8de58aa1e599a8e7abafe5ba94e794a8e5b182e7a88be5ba8fe6b581e7a88be58f8ae4bba3e7a081" target="_blank"></a>三：服务器端应用层程序流程及代码</h1>
<p></p><div class="story_image_container story_block_image"><div class="story_image"><img src="" name="images/QQ截图20160525233842.png" alt="enter description here" title="QQ截图20160525233842.png"></div><br><div class="story_image_caption ">QQ截图20160525233842.png</div></div><br>
<strong>监视端口，等待连接</strong><p></p>
<pre class="xiaoshujiang_code_container"><code class="language-java hljs">
<span class="hljs-comment">//开启一个线程监视用户的请求</span>
<span class="hljs-keyword">new</span> Thread(){

<span class="hljs-annotation">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
    <span class="hljs-keyword">try</span>{
        <span class="hljs-comment">// 1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口，并监听此端口</span>
        ServerSocket serverSocket = <span class="hljs-keyword">new</span> ServerSocket(<span class="hljs-number">8099</span>);
        Socket socket = <span class="hljs-keyword">null</span>;

        <span class="hljs-comment">// 2.调用accept()方法开始监听，等待客户端的连接</span>
        System.out.println(<span class="hljs-string">"Server Started，waiting for User request at port 8099: "</span>);
        <span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) {<span class="hljs-comment">// 循环监听等待客户端的连接</span>
            socket = serverSocket.accept();<span class="hljs-comment">// 调用accept()方法开始监听，等待客户端的连接</span>
            ServerToUserThread userThread = <span class="hljs-keyword">new</span> ServerToUserThread(mSocketList,socket);<span class="hljs-comment">// 创建一个新的线程响应客户端的连接</span>
            userThread.start();<span class="hljs-comment">// 启动线程</span>
            System.out.println(<span class="hljs-string">"用户发起请求，地址："</span>+socket.getInetAddress());
        }
    }
    <span class="hljs-keyword">catch</span> (Exception e) {
        e.printStackTrace();
    }
}
 
}.start();

    
<span class="hljs-comment">//监视设备的连接</span>
<span class="hljs-keyword">try</span> {
    <span class="hljs-comment">// 1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口，并监听此端口</span>
    ServerSocket serverSocket = <span class="hljs-keyword">new</span> ServerSocket(<span class="hljs-number">8090</span>);
    Socket socket = <span class="hljs-keyword">null</span>;

    <span class="hljs-comment">// 2.调用accept()方法开始监听，等待客户端的连接</span>
    System.out.println(<span class="hljs-string">"Server Started，waiting for devices connect at port 8090:"</span>);
    <span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) {<span class="hljs-comment">// 循环监听等待客户端的连接</span>
        socket = serverSocket.accept();<span class="hljs-comment">// 调用accept()方法开始监听，等待客户端的连接</span>
        ServerToDeviceThead serverThread = <span class="hljs-keyword">new</span> ServerToDeviceThead(socket);<span class="hljs-comment">// 创建一个新的线程响应客户端的连接</span>
        serverThread.start();<span class="hljs-comment">// 启动线程</span>
        mSocketList.add(serverThread);<span class="hljs-comment">//储存连接信息</span>
        showInfo(socket);

    }

} <span class="hljs-keyword">catch</span> (IOException e) {
    <span class="hljs-comment">// TODO Auto-generated catch block</span>
    e.printStackTrace();
}



</code></pre>
<p><strong>ServerToDeviceThread类主要执行的内容：</strong></p>
<pre class="xiaoshujiang_code_container"><code class="language-java hljs"><span class="hljs-comment">// 获取输入流，并读取客户端信息</span>
<span class="hljs-keyword">if</span>(!getIn_Out_stream())
{
    System.out.println(<span class="hljs-string">"获取输入输出流错误"</span>);
    Close();
    <span class="hljs-keyword">return</span>;
}

<span class="hljs-keyword">long</span> keepAliveTime = Date_TimeStamp.timeStamp();
<span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>){
    <span class="hljs-comment">//登录检测</span>
    <span class="hljs-keyword">if</span>(!mIsSginIn){
        <span class="hljs-keyword">try</span> {
            socket.setSoTimeout(<span class="hljs-number">20000</span>);
        } <span class="hljs-keyword">catch</span> (SocketException e) {
            <span class="hljs-comment">// TODO Auto-generated catch block</span>
            e.printStackTrace();
        }
        <span class="hljs-comment">//等待登录请求</span>
        <span class="hljs-keyword">if</span>(mToDevices.WaitSignIn(mSignInfo)){
            System.out.println(<span class="hljs-string">"设备登录请求到达，设备号："</span>+mSignInfo.device+<span class="hljs-string">"用户名："</span>+mSignInfo.userName);
            <span class="hljs-comment">//用户和设备验证</span>
            <span class="hljs-keyword">if</span>(!SignInVerify()){<span class="hljs-comment">//验证失败</span>
                System.out.println(<span class="hljs-string">"登录验证失败！！！！"</span>);
                <span class="hljs-keyword">break</span>;
            }
            System.out.println(<span class="hljs-string">"设备登录成功!!设备号："</span>+mSignInfo.device+<span class="hljs-string">"用户名："</span>+mSignInfo.userName);
            mIsSginIn = <span class="hljs-keyword">true</span>;
            <span class="hljs-keyword">try</span> {
                socket.setSoTimeout(<span class="hljs-number">5000</span>);
            } <span class="hljs-keyword">catch</span> (SocketException e) {
                <span class="hljs-comment">// TODO Auto-generated catch block</span>
                e.printStackTrace();
            }
            <span class="hljs-keyword">continue</span>;
        }
        <span class="hljs-keyword">if</span>(Date_TimeStamp.timeStamp()-startTime&gt;<span class="hljs-number">20</span>){<span class="hljs-comment">//20s还没有登录则关闭连接</span>
            System.out.println(<span class="hljs-string">"等待登录请求超时"</span>);
            Close();
        }
        <span class="hljs-keyword">continue</span>;
    }
    
    <span class="hljs-comment">//心跳保持包,5分钟一次</span>
    <span class="hljs-keyword">if</span>(Date_TimeStamp.timeStamp()-keepAliveTime&gt;=<span class="hljs-number">300</span>){
        keepAliveTime = Date_TimeStamp.timeStamp();
        <span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;
        <span class="hljs-keyword">for</span>(;i&lt;<span class="hljs-number">5</span>;++i){
            <span class="hljs-keyword">if</span>(!mToDevices.KeepAlive(mSignInfo.device)){
                System.out.println(<span class="hljs-string">"心跳保持失败,正在重试,重试次数："</span>+i);
                <span class="hljs-keyword">continue</span>;
            }
            System.out.println(<span class="hljs-string">"链路保持成功！"</span>);
        }
        <span class="hljs-keyword">if</span>(i==<span class="hljs-number">5</span>)
            System.out.println(<span class="hljs-string">"心跳保持失败!!!"</span>);
    }

}
</code></pre>
<p><strong>手机端与服务器端跟服务器端与设备端原理一样，只是在多了一个查询设备的过程</strong></p>
<pre class="xiaoshujiang_code_container"><code class="language-java hljs">
<span class="hljs-comment">//从在线设备列表中获得该设备号的设备通信的对象</span>
ToDevices toDevice = <span class="hljs-keyword">null</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>;i&lt;mSocketList.size();++i) {
    <span class="hljs-keyword">if</span>(!mSocketList.get(i).IsAlive())<span class="hljs-comment">//已经关闭连接了，可以移除</span>
        mSocketList.remove(i);
    <span class="hljs-keyword">else</span>{<span class="hljs-comment">//连接还正常（设备在线）//判断是否与要通信的设备名相同</span>
        <span class="hljs-keyword">if</span>(mSocketList.get(i).mSignInfo.device.equals(device)){
            toDevice = mSocketList.get(i).mToDevices;
            <span class="hljs-keyword">break</span>;
        }
    }
}
<span class="hljs-keyword">if</span>(toDevice==<span class="hljs-keyword">null</span>){
    System.out.println(<span class="hljs-string">"该设备没有登录,无法连接到设备！！！"</span>);
    Close();
    <span class="hljs-keyword">return</span>;
}
<span class="hljs-comment">//这里利用获得的ToDevices对象跟设备进行通信即可</span>
</code></pre>
<h1 id="e59b9befbc9ae6898be69cbae7abafe5ba94e794a8e5b182e7a88be5ba8fe6b581e7a88be58f8ae4bba3e7a081"><a name="e59b9befbc9ae6898be69cbae7abafe5ba94e794a8e5b182e7a88be5ba8fe6b581e7a88be58f8ae4bba3e7a081" target="_blank"></a>四：手机端应用层程序流程及代码</h1>
<p></p><div class="story_image_container story_block_image"><div class="story_image"><img src="" name="images/QQ截图20160525234016.png" alt="enter description here" title="QQ截图20160525234016.png"></div><br><div class="story_image_caption ">QQ截图20160525234016.png</div></div><br>
移动端较为简单，只是很费时间。<p></p>
<ul>
<li><p>需要注意的是，与服务器和设备之间的通信不同，虽然都是使用socket进行通信，前者建立的连接在设备正常在线过程中会一直保持，并使用心跳包进行链路保持，但手机和服务器之间的通信是使用的无连接通信，如同http一样，即建立连接--&gt;发起请求--&gt;请求响应--&gt;关闭连接。无需长期保持，因此，服务器需要使用session来保存用户登录信息。用户登录时，服务器会发送一个session码给用户，用户收到后在后面的每一次请求中都会在消息帧中携带这个session码来作为身份验证的依据。</p></li>
<li><p>另一个需要注意的是，Android由于有UI界面，即主线程为UI线程，而网络操作往往很耗费时间，为了避免在等待网络响应的时候UI线程阻塞而导致UI界面假死（程序失去响应）的情况，所有的网络操作一定要记得在新的线程中操作。如果操作后还要修改UI线程中的东西或者向UI线程中返回值，可以使用Runnable来处理网络操作，Handler来进行处理网络操作结束后的UI操作，比如登录：</p></li>
</ul>
<pre class="xiaoshujiang_code_container"><code class="language-java hljs">Handler SignInHandler = <span class="hljs-keyword">new</span> Handler() {
    <span class="hljs-annotation">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span><span class="hljs-params">(Message msg)</span> </span>{
        <span class="hljs-keyword">super</span>.handleMessage(msg);
        Bundle data = msg.getData();
        <span class="hljs-keyword">boolean</span> result = data.getBoolean(<span class="hljs-string">"result"</span>,<span class="hljs-keyword">false</span>);
        <span class="hljs-keyword">if</span> ( result) {
            Toast.makeText(getApplicationContext(), <span class="hljs-string">"登录成功"</span>, Toast.LENGTH_SHORT).show();
        } <span class="hljs-keyword">else</span> {
            Toast.makeText(getApplicationContext(), <span class="hljs-string">"登录失败"</span>, Toast.LENGTH_SHORT).show();
        }
    }
};

<span class="hljs-javadoc">/**
 * 网络操作相关的子线程
 */</span>
Runnable SignIn = <span class="hljs-keyword">new</span> Runnable() {

    <span class="hljs-annotation">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// TODO</span>
        <span class="hljs-comment">// 在这里进行 http request.网络请求相关操作</span>
        <span class="hljs-keyword">boolean</span> result = mToServer.SignIn(mUser);
        Message msg = <span class="hljs-keyword">new</span> Message();
        Bundle data = <span class="hljs-keyword">new</span> Bundle();
        data.putBoolean(<span class="hljs-string">"result"</span>, result);
        msg.setData(data);
        SignInHandler.sendMessage(msg);
    }
};

</code></pre>
<p>然后调用</p>
<pre class="xiaoshujiang_code_container"><code class="language-java hljs"><span class="hljs-keyword">new</span> Thread(SignIn).start();
</code></pre>
</div>

</div></div>
</body></html>

